home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / trace / tcpdump-2.2.1 / bpf / util / rarpd / rarpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-16  |  17.9 KB  |  793 lines

  1. /*
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that: (1) source code distributions
  7.  * retain the above copyright notice and this paragraph in its entirety, (2)
  8.  * distributions including binary code include the above copyright notice and
  9.  * this paragraph in its entirety in the documentation or other materials
  10.  * provided with the distribution, and (3) all advertising materials mentioning
  11.  * features or use of this software display the following acknowledgement:
  12.  * ``This product includes software developed by the University of California,
  13.  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  14.  * the University nor the names of its contributors may be used to endorse
  15.  * or promote products derived from this software without specific prior
  16.  * written permission.
  17.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  18.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  19.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21. #ifndef lint
  22. char copyright[] =
  23. "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
  24.  All rights reserved.\n";
  25. #endif /* not lint */
  26.  
  27. #ifndef lint
  28. static char rcsid[] =
  29.     "@(#) $Header: rarpd.c,v 1.14 92/04/16 18:07:24 leres Exp $ (LBL)";
  30. #endif
  31.  
  32.  
  33. /*
  34.  * rarpd - Reverse ARP Daemon
  35.  *
  36.  * Usage:    rarpd -a [ -f ] [ hostname ]
  37.  *        rarpd [ -f ] interface [ hostname ]
  38.  *
  39.  * 'hostname' is optional solely for backwards compatibility with Sun's rarpd.
  40.  * Currently, the argument is ignored.
  41.  */
  42.  
  43. #include <stdio.h>
  44. #include <syslog.h>
  45. #include <string.h>
  46. #include <strings.h>
  47. #include <sys/types.h>
  48. /* SunOS 4.x defines this while 3.x does not. */
  49. #ifdef __sys_types_h
  50. #define SUNOS4
  51. #endif
  52. #include <sys/time.h>
  53. #include <net/bpf.h>
  54. #include <sys/socket.h>
  55. #include <sys/ioctl.h>
  56. #include <net/if.h>
  57. #include <netinet/in.h>
  58. #include <netinet/if_ether.h>
  59. #include <sys/errno.h>
  60. #include <sys/file.h>
  61. #include <netdb.h>
  62. #include <arpa/inet.h>
  63.  
  64. #ifdef SUNOS4
  65. #include <dirent.h>
  66. #else
  67. #include <sys/dir.h>
  68. #endif
  69.  
  70. /*
  71.  * Map field names in ether_arp struct.  What a pain in the neck.
  72.  */
  73. #ifndef SUNOS4
  74. #undef arp_sha
  75. #undef arp_spa
  76. #undef arp_tha
  77. #undef arp_tpa
  78. #define arp_sha arp_xsha
  79. #define arp_spa arp_xspa
  80. #define arp_tha arp_xtha
  81. #define arp_tpa arp_xtpa
  82. #endif
  83.  
  84. #ifndef __GNUC__
  85. #define inline
  86. #endif
  87.  
  88. extern int errno;
  89.  
  90. /*
  91.  * The structure for each interface.
  92.  */
  93. struct if_info {
  94.     int    ii_fd;        /* BPF file descriptor */
  95.     u_char    ii_eaddr[6];    /* Ethernet address of this interface */
  96.     u_long    ii_ipaddr;    /* IP address of this interface */
  97.     u_long    ii_netmask;    /* subnet or net mask */
  98.     struct if_info *ii_next;
  99. };
  100.  
  101. /*
  102.  * The list of all interfaces that are being listened to.  rarp_loop()
  103.  * "selects" on the descriptors in this list.
  104.  */
  105. struct if_info *iflist;
  106.  
  107. extern char *malloc();
  108. extern void exit();
  109.  
  110. u_long ipaddrtonetmask();
  111. void init_one();
  112. void init_all();
  113. void rarp_loop();
  114. void lookup_eaddr();
  115. void lookup_ipaddr();
  116. int rarp_open();
  117. int rarp_bootable();
  118. void usage();
  119. void rarp_process();
  120. void rarp_reply();
  121. void update_arptab();
  122. char *intoa();
  123.  
  124. void
  125. main(argc, argv)
  126.     int argc;
  127.     char **argv;
  128. {
  129.     int op, pid, devnull, f;
  130.     char *ifname, *hostname, *name;
  131.  
  132.     int aflag = 0;        /* listen on "all" interfaces  */
  133.     int fflag = 0;        /* don't fork */
  134.  
  135.     extern char *optarg;
  136.     extern int optind, opterr;
  137.  
  138.     if (name = strrchr(argv[0], '/'))
  139.         ++name;
  140.     else
  141.         name = argv[0];
  142.     if (*name == '-')
  143.         ++name;
  144.  
  145.     /*
  146.      * All error reporting is done through syslogs.
  147.      */
  148.     openlog(name, LOG_PID | LOG_CONS, LOG_DAEMON);
  149.  
  150.     opterr = 0;
  151.     while ((op = getopt(argc, argv, "af")) != EOF) {
  152.         switch (op) {
  153.         case 'a':
  154.             ++aflag;
  155.             break;
  156.  
  157.         case 'f':
  158.             ++fflag;
  159.             break;
  160.  
  161.         default:
  162.             usage();
  163.             /* NOTREACHED */
  164.         }
  165.     }
  166.     ifname = argv[optind++];
  167.     hostname =  ifname ? argv[optind] : 0;
  168.     if ((aflag && ifname) || (!aflag && ifname == 0))
  169.         usage();
  170.  
  171.     if (aflag)
  172.         init_all();
  173.     else
  174.         init_one(ifname);
  175.  
  176.     if (!fflag) {
  177.         pid = fork();
  178.         if (pid > 0)
  179.             /* Parent exits, leaving child in background. */
  180.             exit(0);
  181.         else if (pid == -1) {
  182.             syslog(LOG_ERR, "cannot fork");
  183.             exit(1);
  184.         }
  185.  
  186.         /* Fade into the background */
  187.         f = open("/dev/tty", O_RDWR);
  188.         if (f >= 0) {
  189.             if (ioctl(f, TIOCNOTTY, 0) < 0)
  190.                 syslog(LOG_ERR, "TIOCNOTTY: %m");
  191.             (void) close(f);
  192.         }
  193.         (void) chdir("/");
  194.         (void) setpgrp(0, getpid());
  195.         devnull = open("/dev/null", O_RDWR);
  196.         if (devnull >= 0) {
  197.             (void) dup2(devnull, 0);
  198.             (void) dup2(devnull, 1);
  199.             (void) dup2(devnull, 2);
  200.             if (devnull > 2)
  201.                 (void) close(devnull);
  202.         }
  203.     }
  204.     rarp_loop();
  205. }
  206.  
  207. /*
  208.  * Add 'ifname' to the interface list.  Lookup its IP address and network
  209.  * mask and Ethernet address, and open a BPF file for it.
  210.  */
  211. void
  212. init_one(ifname)
  213.     char *ifname;
  214. {
  215.     struct if_info *p;
  216.  
  217.  
  218.     p = (struct if_info *)malloc(sizeof(*p));
  219.     if (p == 0) {
  220.         syslog(LOG_ERR, "malloc: %m");
  221.         exit(1);
  222.     }
  223.     p->ii_next = iflist;
  224.     iflist = p;
  225.  
  226.     p->ii_fd = rarp_open(ifname);
  227.     lookup_eaddr(p->ii_fd, p->ii_eaddr);
  228.     lookup_ipaddr(ifname, &p->ii_ipaddr, &p->ii_netmask);
  229. }
  230.  
  231. /*
  232.  * Initialize all "candidate" interfaces that are in the system
  233.  * configuration list.  A "candidate" is up, not loopback and not
  234.  * point to point.
  235.  */
  236. void
  237. init_all()
  238. {
  239.     int fd;
  240.     int n;
  241.     struct ifreq ibuf[8], *ifrp;
  242.     struct ifconf ifc;
  243.  
  244.     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  245.         syslog(LOG_ERR, "socket: %m");
  246.         exit(1);
  247.     }
  248.     ifc.ifc_len = sizeof ibuf;
  249.     ifc.ifc_buf = (caddr_t)ibuf;
  250.     if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
  251.         ifc.ifc_len < sizeof(struct ifreq)) {
  252.         syslog(LOG_ERR, "SIOCGIFCONF: %m");
  253.         exit(1);
  254.     }
  255.     ifrp = ibuf;
  256.     n = ifc.ifc_len / sizeof(*ifrp);
  257.     for (; --n >= 0; ++ifrp) {
  258.         if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {
  259.             syslog(LOG_ERR, "SIOCGIFFLAGS: %m");
  260.             exit(1);
  261.         }
  262.         if ((ifrp->ifr_flags & IFF_UP) == 0 ||
  263.             ifrp->ifr_flags & IFF_LOOPBACK ||
  264.             ifrp->ifr_flags & IFF_POINTOPOINT)
  265.             continue;
  266.         init_one(ifrp->ifr_name);
  267.     }
  268.     (void)close(fd);
  269. }
  270.  
  271. void
  272. usage()
  273. {
  274.     (void)fprintf(stderr, "usage: rarpd [ -af ] [ interface ]\n");
  275.     exit(1);
  276. }
  277.  
  278. static int
  279. bpf_open()
  280. {
  281.     int fd;
  282.     int n = 0;
  283.     char device[sizeof "/dev/bpf000"];
  284.  
  285.     /*
  286.      * Go through all the minors and find one that isn't in use.
  287.      */
  288.     do {
  289.         (void)sprintf(device, "/dev/bpf%d", n++);
  290.         fd = open(device, O_RDWR);
  291.     } while (fd < 0 && errno == EBUSY);
  292.  
  293.     if (fd < 0) {
  294.         syslog(LOG_ERR, "%s: %m", device);
  295.         exit(-1);
  296.     }
  297.     return fd;
  298. }
  299.  
  300. /*
  301.  * Open a BPF file and attach it to the interface named 'device'.
  302.  * Set immediate mode, and set a filter that accepts only RARP requests.
  303.  */
  304. int
  305. rarp_open(device)
  306.     char *device;
  307. {
  308.     int fd;
  309.     struct ifreq ifr;
  310.     u_int dlt;
  311.     int immediate;
  312.  
  313.     static struct bpf_insn insns[] = {
  314.         BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 12),
  315.         BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ETHERTYPE_REVARP, 0, 3),
  316.         BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 20),
  317.         BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, REVARP_REQUEST, 0, 1),
  318.         BPF_STMT(BPF_RET|BPF_K, sizeof(struct ether_arp) +
  319.              sizeof(struct ether_header)),
  320.         BPF_STMT(BPF_RET|BPF_K, 0),
  321.     };
  322.     static struct bpf_program filter = {
  323.         sizeof insns / sizeof(insns[0]),
  324.         insns
  325.     };
  326.  
  327.     fd = bpf_open();
  328.     /*
  329.      * Set immediate mode so packets are processed as they arrive.
  330.      */
  331.     immediate = 1;
  332.     if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) {
  333.         syslog(LOG_ERR, "BIOCIMMEDIATE: %m");
  334.         exit(1);
  335.     }
  336.     (void)strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
  337.     if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
  338.         syslog(LOG_ERR, "BIOCSETIF: %m");
  339.         exit(1);
  340.     }
  341.     /*
  342.      * Check that the data link layer is an Ethernet; this code won't
  343.      * work with anything else.
  344.      */
  345.     if (ioctl(fd, BIOCGDLT, (caddr_t)&dlt) < 0) {
  346.         syslog(LOG_ERR, "BIOCGDLT: %m");
  347.         exit(1);
  348.     }
  349.     if (dlt != DLT_EN10MB) {
  350.         syslog(LOG_ERR, "%s is not an ethernet", device);
  351.         exit(1);
  352.     }
  353.     /*
  354.      * Set filter program.
  355.      */
  356.     if (ioctl(fd, BIOCSETF, (caddr_t)&filter) < 0) {
  357.         syslog(LOG_ERR, "BIOCSETF: %m");
  358.         exit(1);
  359.     }
  360.     return fd;
  361. }
  362.  
  363. /*
  364.  * Perform various sanity checks on the RARP request packet.  Return
  365.  * false on failure and log the reason.
  366.  */
  367. static int
  368. rarp_check(p, len)
  369.     u_char *p;
  370.     int len;
  371. {
  372.     struct ether_header *ep = (struct ether_header *)p;
  373.     struct ether_arp *ap = (struct ether_arp *)(p + sizeof(*ep));
  374.  
  375.     if (len < sizeof(*ep) + sizeof(*ap)) {
  376.         syslog(LOG_ERR, "truncated request");
  377.         return 0;
  378.     }
  379.     /*
  380.      * XXX This test might be better off broken out...
  381.      */
  382.     if (ep->ether_type != ETHERTYPE_REVARP ||
  383.         ap->arp_hrd != ARPHRD_ETHER ||
  384.         ap->arp_op != REVARP_REQUEST ||
  385.         ap->arp_pro != ETHERTYPE_IP ||
  386.         ap->arp_hln != 6 || ap->arp_pln != 4) {
  387.         syslog(LOG_DEBUG, "request fails sanity check");
  388.         return 0;
  389.     }
  390.     if (bcmp((char *)&ep->ether_shost, (char *)&ap->arp_sha, 6) != 0) {
  391.         syslog(LOG_DEBUG, "ether/arp sender address mismatch");
  392.         return 0;
  393.     }
  394.     if (bcmp((char *)&ap->arp_sha, (char *)&ap->arp_tha, 6) != 0) {
  395.         syslog(LOG_DEBUG, "ether/arp target address mismatch");
  396.         return 0;
  397.     }
  398.     return 1;
  399. }
  400.  
  401. #ifndef FD_SETSIZE
  402. #define FD_SET(n, fdp) ((fdp)->fds_bits[0] |= (1 << (n)))
  403. #define FD_ISSET(n, fdp) ((fdp)->fds_bits[0] & (1 << (n)))
  404. #define FD_ZERO(fdp) ((fdp)->fds_bits[0] = 0)
  405. #endif
  406.  
  407. /*
  408.  * Loop indefinitely listening for RARP requests on the
  409.  * interfaces in 'iflist'.
  410.  */
  411. void
  412. rarp_loop()
  413. {
  414.     u_char *buf, *bp, *ep;
  415.     int cc, fd;
  416.     fd_set fds, listeners;
  417.     int bufsize, maxfd = 0;
  418.     struct if_info *ii;
  419.  
  420.     if (iflist == 0) {
  421.         syslog(LOG_ERR, "no interfaces");
  422.         exit(1);
  423.     }
  424.     if (ioctl(iflist->ii_fd, BIOCGBLEN, (caddr_t)&bufsize) < 0) {
  425.         syslog(LOG_ERR, "BIOCGBLEN: %m");
  426.         exit(1);
  427.     }
  428.     buf = (u_char *)malloc((unsigned)bufsize);
  429.     if (buf == 0) {
  430.         syslog(LOG_ERR, "malloc: %m");
  431.         exit(1);
  432.     }
  433.  
  434.     /*
  435.      * Find the highest numbered file descriptor for select().
  436.      * Initialize the set of descriptors to listen to.
  437.      */
  438.     FD_ZERO(&fds);
  439.     for (ii = iflist; ii; ii = ii->ii_next) {
  440.         FD_SET(ii->ii_fd, &fds);
  441.         if (ii->ii_fd > maxfd)
  442.             maxfd = ii->ii_fd;
  443.     }
  444.     while (1) {
  445.         listeners = fds;
  446.         if (select(maxfd + 1, &listeners, (struct fd_set *)0,
  447.                (struct fd_set *)0, (struct timeval *)0) < 0) {
  448.             syslog(LOG_ERR, "select: %m");
  449.             exit(1);
  450.         }
  451.         for (ii = iflist; ii; ii = ii->ii_next) {
  452.             fd = ii->ii_fd;
  453.             if (!FD_ISSET(fd, &listeners))
  454.                 continue;
  455.         again:
  456.             cc = read(fd, (char *)buf, bufsize);
  457.             /* Don't choke when we get ptraced */
  458.             if (cc < 0 && errno == EINTR)
  459.                 goto again;
  460.             /*
  461.              * Due to a SunOS bug, after 2^31 bytes, the
  462.              * file offset overflows and read fails with
  463.              * EINVAL.  The lseek() to 0 will fix things.
  464.              */
  465.             if (cc < 0) {
  466.                 if (errno == EINVAL &&
  467.                     (long)(tell(fd) + bufsize) < 0) {
  468.                     (void)lseek(fd, 0, 0);
  469.                     goto again;
  470.                 }
  471.                 syslog(LOG_ERR, "read: %m");
  472.                 exit(1);
  473.             }
  474.  
  475.             /* Loop through the packet(s) */
  476. #define bhp ((struct bpf_hdr *)bp)
  477.             bp = buf;
  478.             ep = bp + cc;
  479.             while (bp < ep) {
  480.                 register int caplen, hdrlen;
  481.  
  482.                 caplen = bhp->bh_caplen;
  483.                 hdrlen = bhp->bh_hdrlen;
  484.                 if (rarp_check(bp + hdrlen, caplen))
  485.                     rarp_process(ii, bp + hdrlen);
  486.                 bp += BPF_WORDALIGN(hdrlen + caplen);
  487.             }
  488.         }
  489.     }
  490. }
  491.  
  492. #ifndef TFTP_DIR
  493. #define TFTP_DIR "/tftpboot"
  494. #endif
  495.  
  496. /*
  497.  * True if this server can boot the host whose IP address is 'addr'.
  498.  * This check is made by looking in the tftp directory for the
  499.  * configuration file.
  500.  */
  501. int
  502. rarp_bootable(addr)
  503.     u_long addr;
  504. {
  505. #ifdef SUNOS4
  506.     register struct dirent *dent;
  507. #else
  508.     register struct direct *dent;
  509. #endif
  510.     register DIR *d;
  511.     char ipname[9];
  512.     static DIR *dd = 0;
  513.  
  514.     (void)sprintf(ipname, "%08X", addr);
  515.     /*
  516.      * If directory is already open, rewind it.  Otherwise, open it.
  517.      */
  518.     if (d = dd)
  519.         rewinddir(d);
  520.     else {
  521.         if (chdir(TFTP_DIR) == -1) {
  522.             syslog(LOG_ERR, "chdir: %m");
  523.             exit(1);
  524.         }
  525.         d = opendir(".");
  526.         if (d == 0) {
  527.             syslog(LOG_ERR, "opendir: %m");
  528.             exit(1);
  529.         }
  530.         dd = d;
  531.     }
  532.     while (dent = readdir(d))
  533.         if (strncmp(dent->d_name, ipname, 8) == 0)
  534.             return 1;
  535.     return 0;
  536. }
  537.  
  538. /*
  539.  * Given a list of IP addresses, 'alist', return the first address that
  540.  * is on network 'net'; 'netmask' is a mask indicating the network portion
  541.  * of the address.
  542.  */
  543. u_long
  544. choose_ipaddr(alist, net, netmask)
  545.     u_long **alist;
  546.     u_long net;
  547.     u_long netmask;
  548. {
  549.     for (; *alist; ++alist) {
  550.         if ((**alist & netmask) == net)
  551.             return **alist;
  552.     }
  553.     return 0;
  554. }
  555.  
  556. /*
  557.  * Answer the RARP request in 'pkt', on the interface 'ii'.  'pkt' has
  558.  * already been checked for validity.  The reply is overlaid on the request.
  559.  */
  560. void
  561. rarp_process(ii, pkt)
  562.     struct if_info *ii;
  563.     u_char *pkt;
  564. {
  565.     struct ether_header *ep;
  566.     struct hostent *hp;
  567.     u_long target_ipaddr;
  568.     char ename[256];
  569.  
  570.     ep = (struct ether_header *)pkt;
  571.     if (ether_ntohost(ename, &ep->ether_shost) != 0 ||
  572.         (hp = gethostbyname(ename)) == 0)
  573.         return;
  574.     /*
  575.      * Choose correct address from list.
  576.      */
  577.     if (hp->h_addrtype != AF_INET) {
  578.         syslog(LOG_ERR, "cannot handle non IP addresses");
  579.         exit(1);
  580.     }
  581.     target_ipaddr = choose_ipaddr((u_long **)hp->h_addr_list,
  582.                       ii->ii_ipaddr & ii->ii_netmask,
  583.                       ii->ii_netmask);
  584.     if (target_ipaddr == 0) {
  585.         syslog(LOG_ERR, "cannot find %s on net %s",
  586.                ename, intoa(ii->ii_ipaddr & ii->ii_netmask));
  587.         return;
  588.     }
  589.     if (rarp_bootable(target_ipaddr))
  590.         rarp_reply(ii, ep, target_ipaddr);
  591. }
  592.  
  593. /*
  594.  * Lookup the ethernet address of the interface attached to the BPF
  595.  * file descriptor 'fd'; return it in 'eaddr'.
  596.  */
  597. void
  598. lookup_eaddr(fd, eaddr)
  599.     int fd;
  600.     u_char *eaddr;
  601. {
  602.     struct ifreq ifr;
  603.  
  604.     /* Use BPF descriptor to get ethernet address. */
  605.     if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
  606.         syslog(LOG_ERR, "SIOCGIFADDR: %m");
  607.         exit(1);
  608.     }
  609.     bcopy((char *)&ifr.ifr_addr.sa_data[0], (char *)eaddr, 6);
  610. }
  611.  
  612. /*
  613.  * Lookup the IP address and network mask of the interface named 'ifname'.
  614.  */
  615. void
  616. lookup_ipaddr(ifname, addrp, netmaskp)
  617.     char *ifname;
  618.     u_long *addrp;
  619.     u_long *netmaskp;
  620. {
  621.     int fd;
  622.     struct ifreq ifr;
  623.  
  624.     /* Use data gram socket to get IP address. */
  625.     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  626.         syslog(LOG_ERR, "socket: %m");
  627.         exit(1);
  628.     }
  629.     (void)strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
  630.     if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
  631.         syslog(LOG_ERR, "SIOCGIFADDR: %m");
  632.         exit(1);
  633.     }
  634.     *addrp = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  635.     if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
  636.         perror("SIOCGIFNETMASK");
  637.         exit(1);
  638.     }
  639.     *netmaskp = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  640.     /*
  641.      * If SIOCGIFNETMASK didn't work, figure out a mask from
  642.      * the IP address class.
  643.      */
  644.     if (*netmaskp == 0)
  645.         *netmaskp = ipaddrtonetmask(*addrp);
  646.  
  647.     (void)close(fd);
  648. }
  649.  
  650. /*
  651.  * Poke the kernel arp tables with the ethernet/ip address combinataion
  652.  * given.  When processing a reply, we must do this so that the booting
  653.  * host (i.e. the guy running rarpd), won't try to ARP for the hardware
  654.  * address of the guy being booted (he cannot answer the ARP).
  655.  */
  656. void
  657. update_arptab(ep, ipaddr)
  658.     u_char *ep;
  659.     u_long ipaddr;
  660. {
  661.     int s;
  662.     struct arpreq request;
  663.     struct sockaddr_in *sin;
  664.  
  665.     request.arp_flags = 0;
  666.     sin = (struct sockaddr_in *)&request.arp_pa;
  667.     sin->sin_family = AF_INET;
  668.     sin->sin_addr.s_addr = ipaddr;
  669.     request.arp_ha.sa_family = AF_UNSPEC;
  670.     bcopy((char *)ep, (char *)request.arp_ha.sa_data, 6);
  671.  
  672.     s = socket(AF_INET, SOCK_DGRAM, 0);
  673.     if (ioctl(s, SIOCSARP, (caddr_t)&request) < 0)
  674.         syslog(LOG_ERR, "SIOCSARP: %m");
  675.     (void)close(s);
  676. }
  677.  
  678. /*
  679.  * Build a reverse ARP packet and sent it out on the interface.
  680.  * 'ep' points to a valid REVARP_REQUEST.  The REVARP_REPLY is built
  681.  * on top of the request, then written to the network.
  682.  *
  683.  * RFC 903 defines the ether_arp fields as follows.  The following comments
  684.  * are taken (more or less) straight from this document.
  685.  *
  686.  * REVARP_REQUEST
  687.  *
  688.  * arp_sha is the hardware address of the sender of the packet.
  689.  * arp_spa is undefined.
  690.  * arp_tha is the 'target' hardware address.
  691.  *   In the case where the sender wishes to determine his own
  692.  *   protocol address, this, like arp_sha, will be the hardware
  693.  *   address of the sender.
  694.  * arp_tpa is undefined.
  695.  *
  696.  * REVARP_REPLY
  697.  *
  698.  * arp_sha is the hardware address of the responder (the sender of the
  699.  *   reply packet).
  700.  * arp_spa is the protocol address of the responder (see the note below).
  701.  * arp_tha is the hardware address of the target, and should be the same as
  702.  *   that which was given in the request.
  703.  * arp_tpa is the protocol address of the target, that is, the desired address.
  704.  *
  705.  * Note that the requirement that arp_spa be filled in with the responder's
  706.  * protocol is purely for convenience.  For instance, if a system were to use
  707.  * both ARP and RARP, then the inclusion of the valid protocol-hardware
  708.  * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent
  709.  * ARP request.
  710.  */
  711. void
  712. rarp_reply(ii, ep, ipaddr)
  713.     struct if_info *ii;
  714.     struct ether_header *ep;
  715.     u_long ipaddr;
  716. {
  717.     int n;
  718.     struct ether_arp *ap = (struct ether_arp *)(ep + 1);
  719.     int len;
  720.  
  721.     update_arptab((u_char *)&ap->arp_sha, ipaddr);
  722.  
  723.     /*
  724.      * Build the rarp reply by modifying the rarp request in place.
  725.      */
  726.     ap->arp_op = REVARP_REPLY;
  727.  
  728.     bcopy((char *)&ap->arp_sha, (char *)&ep->ether_dhost, 6);
  729.     bcopy((char *)ii->ii_eaddr, (char *)&ep->ether_shost, 6);
  730.     bcopy((char *)ii->ii_eaddr, (char *)&ap->arp_sha, 6);
  731.  
  732.     bcopy((char *)&ipaddr, (char *)ap->arp_tpa, 4);
  733.     /* Target hardware is unchanged. */
  734.     bcopy((char *)&ii->ii_ipaddr, (char *)ap->arp_spa, 4);
  735.  
  736.     len = sizeof(*ep) + sizeof(*ap);
  737.     n = write(ii->ii_fd, (char *)ep, len);
  738.     if (n != len)
  739.         syslog(LOG_ERR, "write: only %d of %d bytes written", n, len);
  740. }
  741.  
  742. /*
  743.  * Get the netmask of an IP address.  This routine is used if
  744.  * SIOCGIFNETMASK doesn't work.
  745.  */
  746. u_long
  747. ipaddrtonetmask(addr)
  748.     u_long addr;
  749. {
  750.     if (IN_CLASSA(addr))
  751.         return IN_CLASSA_NET;
  752.     if (IN_CLASSB(addr))
  753.         return IN_CLASSB_NET;
  754.     if (IN_CLASSC(addr))
  755.         return IN_CLASSC_NET;
  756.     syslog(LOG_DEBUG, "unknown IP address class: %08X", addr);
  757.     exit(1);
  758.     /* NOTREACHED */
  759. }
  760.  
  761. /*
  762.  * A faster replacement for inet_ntoa().
  763.  */
  764. char *
  765. intoa(addr)
  766.     u_long addr;
  767. {
  768.     register char *cp;
  769.     register u_int byte;
  770.     register int n;
  771.     static char buf[sizeof(".xxx.xxx.xxx.xxx")];
  772.  
  773.     cp = &buf[sizeof buf];
  774.     *--cp = '\0';
  775.  
  776.     n = 4;
  777.     do {
  778.         byte = addr & 0xff;
  779.         *--cp = byte % 10 + '0';
  780.         byte /= 10;
  781.         if (byte > 0) {
  782.             *--cp = byte % 10 + '0';
  783.             byte /= 10;
  784.             if (byte > 0)
  785.                 *--cp = byte + '0';
  786.         }
  787.         *--cp = '.';
  788.         addr >>= 8;
  789.     } while (--n > 0);
  790.  
  791.     return cp + 1;
  792. }
  793.